package com.molichuxing.gateway.bff.permission.services.impl;

import com.moli.iov.util.Md5PwdEncoder;
import com.moli.iov.util.api.ApiUtils;
import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.result.ResponseCodeEnum;
import com.molichuxing.framework.result.ResponseResult;
import com.molichuxing.framework.utils.CollectionUtils;
import com.molichuxing.framework.utils.Md5Util;
import com.molichuxing.framework.utils.StringUtil;
import com.molichuxing.gateway.bff.permission.convertor.Convert;
import com.molichuxing.gateway.bff.permission.entity.response.*;
import com.molichuxing.gateway.bff.permission.services.GroupBffService;
import com.molichuxing.gateway.utils.RedisPermissionUtil;
import com.molichuxing.gateway.utils.TokenUtil;
import com.molichuxing.gateway.utils.entity.UserEntity;
import com.molichuxing.services.business.service.DesenseBizService;
import com.molichuxing.services.business.service.GroupBizService;
import com.molichuxing.services.infrastructure.dto.request.create.IovCreateGroupDto;
import com.molichuxing.services.infrastructure.dto.request.modify.IovModifyGroupDto;
import com.molichuxing.services.infrastructure.dto.response.DealerDto;
import com.molichuxing.services.infrastructure.dto.response.IovGroupBindResourceDto;
import com.molichuxing.services.infrastructure.dto.response.IovGroupDto;
import com.molichuxing.services.infrastructure.dto.response.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.GroupSystemTypeEnum;
import com.molichuxing.services.property.OpIovStatusConvertEnum;
import com.molichuxing.services.property.StatusEnum;
import com.molichuxing.services.property.SystemTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service("permissionGroupBffService")
public class GroupBffServiceImpl implements GroupBffService {

    private static final Logger logger = LoggerFactory.getLogger(AccountBffServiceImpl.class);

    @Resource
    private GroupBizService groupBizService;

    @Resource
    private DealerService dealerService;

    @Resource
    private GroupService groupService;

    @Resource
    private TokenUtil tokenUtil;

    @Resource
    private GroupResourceService groupResourceService;

    @Resource
    private ResourceService resourceService;

    @Resource
    private DesenseBizService desenseBizService;

    @Resource
    private IovPermissionService iovPermissionService;

    @Resource
    private AccountGroupService accountGroupService;

    @Resource
    private AccountService accountService;

    @Resource
    private RedisPermissionUtil redisPermissionUtil;

    @Override
    public ResponseResult<Paged<GroupVo>> getGroupList(Map<String, Object> param, int pageNum, int pageSize) throws Exception {
        ResponseResult<Paged<GroupVo>> result = new ResponseResult<Paged<GroupVo>>();
        if (param.get("groupSystemType") != null && Integer.valueOf((String)param.get("groupSystemType")) == GroupSystemTypeEnum.IOV.getValue()) {
            result = getIovGroupList(param, pageNum, pageSize);
        } else {
            result = getOpGroupList(param, pageNum, pageSize);
        }


        List<TabDto> tabList = new ArrayList<>();
        for (GroupSystemTypeEnum tabEnum : GroupSystemTypeEnum.values()) {
            int count = 0;
            if (tabEnum.getValue() != GroupSystemTypeEnum.IOV.getValue()) {
                Map<String, Object> getTabCountParam = new HashMap<>();
                getTabCountParam.put("groupSystemType", tabEnum.getValue());

                count = groupService.getGroupCountByParam(getTabCountParam);
            } else {
                try {
                    ResponseResult<Integer> groupCountResult = iovPermissionService.getGroupCount();
                    if (groupCountResult.getCode() != ResponseCodeEnum.SUCCESS.getCode()) {
                        logger.error("调用车联网获取角色总数接口异常，code ::{},message ::{}", groupCountResult.getCode(), groupCountResult.getMessage());
                        count = 0;
                    } else {
                        count = iovPermissionService.getGroupCount().getData();
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
            TabDto tabDto = new TabDto();
            tabDto.setName(tabEnum.getName());
            tabDto.setType(tabEnum.getValue());
            tabDto.setCount(count);
            tabList.add(tabDto);
        }
        result.getData().setTab(tabList);

        return result;
    }

    private ResponseResult<Paged<GroupVo>> getIovGroupList(Map<String, Object> param, int pageNum, int pageSize) throws Exception {
        ResponseResult<Paged<GroupVo>> result = new ResponseResult<Paged<GroupVo>>();
        Paged<GroupVo> data = new Paged<>();

        Integer status = param.get("status") == null ? null : Integer.parseInt(param.get("status").toString());

        Map<String, Object> getIovGroupParam = new HashMap<>();
        getIovGroupParam.put("roleName", param.get("name"));
        if (status != null && OpIovStatusConvertEnum.getEnum(status) != null) {
            getIovGroupParam.put("status", OpIovStatusConvertEnum.getIovValue(status));
        }
        ResponseResult<Paged<IovGroupDto>> iovResult = iovPermissionService.getGroupListByPage(getIovGroupParam, pageNum, pageSize);
        if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode())
            return result.error(iovResult.getCode(), iovResult.getMessage());

        List<GroupVo> groupVoList = Convert.iovGroupListToGroupVoList(iovResult.getData().getList());
        data.setList(groupVoList);
        data.setTotal(iovResult.getData().getTotal());
        data.setPageSize(iovResult.getData().getPageSize());

        return result.success(ResponseCodeEnum.SUCCESS.getMessage(), data);
    }

    private ResponseResult<Paged<GroupVo>> getOpGroupList(Map<String, Object> param, int pageNum, int pageSize) {

        ResponseResult<Paged<GroupVo>> result = new ResponseResult<Paged<GroupVo>>();
        Paged<GroupVo> data = new Paged<>();
        Paged<GroupDto> pageList = groupBizService.getGroupPageList(param, pageNum, pageSize);
        if (pageList != null && CollectionUtils.isNotEmpty(pageList.getList())) {
            List<GroupVo> groupList = Convert.toGroupVoList(pageList.getList());
            if (param.get("groupSystemType") != null && Integer.valueOf((String)param.get("groupSystemType")) == GroupSystemTypeEnum.DEALER.getValue()) { //经销商
                final Set<Integer> dealerIdSet = new HashSet<>();
                groupList.forEach(group -> {
                    if (group.getDealerId() != null && group.getDealerId() > 0) {
                        dealerIdSet.add(group.getDealerId());
                    }
                });

                if (CollectionUtils.isNotEmpty(dealerIdSet)) {
                    Map<String, Object> getDealerParam = new HashMap<>();
                    getDealerParam.put("dealerIds", dealerIdSet);
                    List<DealerDto> dealerList = dealerService.getDealerListByParam(getDealerParam);  //查询经销商

                    final Map<Integer, String> dealerMap = new HashMap();
                    dealerList.forEach(dealer -> {
                        dealerMap.put(dealer.getDealerId(), dealer.getShortName());
                    });

                    if (dealerMap != null && dealerMap.size() > 0) {
                        groupList.forEach(group -> {
                            group.setDealerName(dealerMap.get(group.getDealerId())); //为角色赋值
                        });
                    }
                }
            }
            data.setList(groupList);
            data.setTotal(pageList.getTotal());
            data.setPageSize(pageList.getPageSize());
        }
        return result.success(ResponseCodeEnum.SUCCESS.getMessage(), data);
    }

    @Override
    public ResponseResult<Boolean> createGroup(GroupCreateVo vo) {
        ResponseResult<Boolean> result = new ResponseResult<>();
        if (vo == null)
            return result.error("角色不能为空", Boolean.FALSE);
        if (vo.getGroupSystemType() == null || vo.getGroupSystemType() <= 0)
            return result.error("系统类型不能为空", Boolean.FALSE);
        if (StringUtil.isEmpty(vo.getGroupName()))
            return result.error("角色名称不能为空", Boolean.FALSE);
        if (StringUtil.isEmpty(vo.getGroupDesc()))
            return result.error("角色描述不能为空", Boolean.FALSE);
        if (vo.getGroupSystemType() == GroupSystemTypeEnum.DEALER.getValue() && (vo.getDealerId() == null || vo.getDealerId() <= 0))
            return result.error("经销商不能为空", Boolean.FALSE);


         //车联网需要调用车联网添加角色接口，op本地库不存车联网数据
        if (vo.getGroupSystemType() == GroupSystemTypeEnum.IOV.getValue()) {
            // 调用车联网添加角色接口
            try {



                IovCreateGroupDto dto = new IovCreateGroupDto();
                dto.setRoleName(vo.getGroupName());
                dto.setMemo(vo.getGroupDesc());
                dto.setStatus(OpIovStatusConvertEnum.getIovValue(vo.getStatus()));
                ResponseResult<Boolean> iovResult = iovPermissionService.createGroup(dto);
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode() || !iovResult.getData()) { //同步失败
                    logger.error("新建车联网角色失败, 返回信息result ::{}", iovResult.getMessage());
                    return result.error("新建车联网角色失败，车联网返回信息：" +iovResult.getMessage());
                }
                return result.success("添加成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error("新建车联网角色失败");
                logger.error(e.getMessage(), e);
                return result.error("新建车联网角色失败");
            }
        } else {
            try {
                //groupName要求唯一性，如果在op，则同一系统中不允许出现同名角色，如果是经销商系统，则同一经销商下不允许有同名角色
                GroupDto currentNameGroup = groupService.getGroupByNameAndDealerId(vo.getGroupSystemType(), vo.getDealerId(), vo.getGroupName());
                if (currentNameGroup != null)
                    return result.error("【" + vo.getGroupName() + "】已存在，不允许重复录入", Boolean.FALSE);

                GroupCreateDto dto = Convert.toGroupCreateDto(vo);

                UserEntity currentLoginUser = tokenUtil.getUser();

                dto.setOperatorAccountId(currentLoginUser.getAccountId()); //操作人id
                dto.setOperatorAccount(currentLoginUser.getRealName()); //操作人姓名

                int id = groupService.createGroup(dto);
                if (id > 0)
                    return result.success("添加成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        return result.error("添加失败", Boolean.FALSE);
    }

    @Override
    public ResponseResult<Boolean> modifyGroup(GroupModifyVo vo) {
        ResponseResult<Boolean> result = new ResponseResult<>();
        if (vo == null)
            return result.error("角色不能为空", Boolean.FALSE);
        if (vo.getGroupSystemType() == null || vo.getGroupSystemType() <= 0)
            return result.error("系统类型不能为空", Boolean.FALSE);
        if (vo.getId() == null || vo.getId() <= 0)
            return result.error("用户id不能为空", Boolean.FALSE);


        //车联网需要调用车联网修改角色接口，op本地库不存车联网数据
        if (vo.getGroupSystemType() == GroupSystemTypeEnum.IOV.getValue()) {
            // 调用车联网修改角色接口
            try {
                IovModifyGroupDto dto = new IovModifyGroupDto();
                dto.setRoleId(vo.getId());
                dto.setRoleName(vo.getGroupName());
                dto.setMemo(vo.getGroupDesc());
                dto.setStatus(OpIovStatusConvertEnum.getIovValue(vo.getStatus()));
                ResponseResult<Boolean> iovResult = iovPermissionService.modifyGroup(dto);
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode() || !iovResult.getData()) { //同步失败
                    logger.error("修改车联网角色失败, 返回信息result ::{}", iovResult.getMessage());
                    return result.error("修改车联网角色失败，车联网返回信息：" +iovResult.getMessage());
                }
                return result.success("修改成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error("修改车联网角色失败");
                logger.error(e.getMessage(), e);
            }

        } else {
            try {
                //获取用角色
                GroupDto oldGroup = groupService.getGroupById(vo.getId());
                if (oldGroup == null) //数据库中没有此用户
                    return result.error("角色不存在，修改失败");

                //检查在相同机构下（如果是op就同一类型下）是否存在同名角色，如果存在，提示保存失败
                GroupDto currentNameGroup = groupService.getGroupByNameAndDealerId(oldGroup.getGroupSystemType().getValue(), oldGroup.getDealerId(), vo.getGroupName());
                if (currentNameGroup != null && currentNameGroup.getId() != vo.getId())
                    return result.error("【" + vo.getGroupName() + "】" + "已存在，不允许重复录入", Boolean.FALSE);

                GroupModifyDto dto = Convert.toGroupModifyDto(vo);

                UserEntity currentLoginUser = tokenUtil.getUser();

                dto.setOperatorAccountId(currentLoginUser.getAccountId()); //操作人id
                dto.setOperatorAccount(currentLoginUser.getRealName()); //操作人姓名

                int row = groupService.modifyGroup(dto);
                if (row > 0) { //修改完成后, 与此角色关联的用户全部强制登出
                    Map<String, Object> getAccountGroupParam = new HashMap<>();
                    getAccountGroupParam.put("groupId", dto.getId());

                    List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);
                    if (CollectionUtils.isNotEmpty(accountGroupList)) {
                        final List<Integer> accountIds = new ArrayList<>();
                        accountGroupList.forEach(accountGroup -> {
                            accountIds.add(accountGroup.getAccountId());
                        });

                        Map<String, Object> getAccountParam = new HashMap<>();
                        getAccountParam.put("ids", accountIds);
                        List<AccountDto> accountList = accountService.getAccountByParam(getAccountParam);
                        accountList.forEach(account -> {  //强制登出
                            tokenUtil.deleteUserByAccount(account);
                        });

                        if (dto.getStatus() == StatusEnum.OFF.getValue()) { //角色被禁用，删除用户与角色的关联关系
                            Map<String, Object> deleteAccountGroupParam = new HashMap<>();
                            deleteAccountGroupParam.put("groupId", dto.getId());
                            accountGroupService.deleteByParam(deleteAccountGroupParam); //删除用户与角色的关联关系
                        }

                    }

                    if (dto.getStatus() == StatusEnum.OPEN.getValue()) { //重写redis
                        redisPermissionUtil.resourceToRedis(oldGroup.getId(), oldGroup.getGroupSystemType());
                    } else { //删除redis数据
                        redisPermissionUtil.deleteResourceByGroupId(oldGroup);
                    }

                }
                return result.success("修改成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        return result.error("修改失败", Boolean.FALSE);
    }

    @Override
    public OpGroupAndIovGroupVo getGroupListInModifyAccountPage(int systemType, int dealerId, String account) throws Exception {
        OpGroupAndIovGroupVo result = new OpGroupAndIovGroupVo();
        if (systemType <= 0 || (systemType == SystemTypeEnum.DEALER.getValue() && dealerId <= 0)) {
            logger.error("param invaild system ::{}, dealerId ::{}", systemType, dealerId);
            throw new IllegalArgumentException("systemType || dealerId INVAILD");
        }
        Map<String, Object> getGroupParam = new HashMap<>();
        getGroupParam.put("groupSystemType", systemType);
        getGroupParam.put("dealerId", dealerId);
        getGroupParam.put("status", StatusEnum.OPEN.getValue());
        List<GroupDto> opDataList = groupService.getGroupListByParm(getGroupParam);
        if (CollectionUtils.isNotEmpty(opDataList))
            result.setOpGroup(Convert.toGroupVoList(opDataList));

        if (systemType == SystemTypeEnum.OP.getValue()) { //如果是op用户，查询车联网角色
            if (!StringUtil.isEmpty(account)) { //有用户名证明是修改，根据用户名查询
                ResponseResult<List<IovGroupDto>> iovResult = iovPermissionService.getAccountGroupByAccount(account);
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode()) { //同步失败
                    logger.error("调用车联网接口失败, 返回信息result ::{}", iovResult.getMessage());
                } else {
                    result.setIovGroup(Convert.iovGroupListToGroupVoList(iovResult.getData()));
                }
            } else { //没有用户名，证明是添加，直接查全部
                ResponseResult<List<IovGroupDto>> iovResult = iovPermissionService.getGroupList();
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode()) { //同步失败
                    logger.error("调用车联网接口失败, 返回信息result ::{}", iovResult.getMessage());
                } else {
                    result.setIovGroup(Convert.iovGroupListToGroupVoList(iovResult.getData()));
                }
            }

        }
        return result;
    }

    @Override
    public GroupBindResourceVo getPermissionTree(int groupId, int groupSystemType) {
        GroupBindResourceVo result = new GroupBindResourceVo();
        if (groupSystemType <= 0 || groupId <= 0) {
            logger.error("param invalid ,groupId ::{}, groupSystemType ::{}", groupId, groupSystemType);
            throw new IllegalArgumentException("groupSystemType or roleId invalid");
        }
        if (groupSystemType == GroupSystemTypeEnum.IOV.getValue()) {

            //T调用车联网接口获取权限
            try {
                ResponseResult<IovGroupBindResourceDto> iovResult = iovPermissionService.getGroupPermission(groupId);
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode()) { //同步失败
                    logger.error("调用车联网获取权限接口失败, 返回信息result ::{}", iovResult.getMessage());
                }
                if (iovResult.getData() != null) {
                    List<Integer> bindResourceIdList = iovResult.getData().getGroupBindpermissionIds();
                    List<ResourceDto> resourceTree = Convert.toResourceDtoList(iovResult.getData().getPermissionTree());

                    result.setGroupBindpermissionIds(bindResourceIdList);
                    result.setPermissionTree(resourceTree);
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        } else {
            try {
                Map<String, Object> getGroupResourceParam = new HashMap<>();
                getGroupResourceParam.put("groupId", groupId);

                //将绑定的权限id放进集合
                final List<Integer> bindResourceIdList = new ArrayList<>();
                List<GroupResourceDto> groupResourceList = groupResourceService.getGroupResourceListByParm(getGroupResourceParam);
                if (CollectionUtils.isNotEmpty(groupResourceList)) {
                    groupResourceList.forEach(groupResourceDto -> {
                        bindResourceIdList.add(groupResourceDto.getResourceId());
                    });
                }

                List<ResourceDto> resourceTree = resourceService.getResoureTree(groupSystemType);

                result.setGroupBindpermissionIds(bindResourceIdList);
                result.setPermissionTree(resourceTree);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        return result;
    }

    /**
     * 通过id获取角色绑定的脱敏字段
     *
     * @param groupId
     * @return
     */
    public List<DesenseVo> getDesenseByGroupId(int groupId) {
        if (groupId <= 0)
            throw new IllegalArgumentException("groupId invalid :" + groupId);

        GroupBindDesenseVo result = new GroupBindDesenseVo();

        List<DesenseVo> dataList = Convert.toDesenseVoList(desenseBizService.getDesenseByGroupId(groupId));

        return dataList;
    }

    /**
     * 创建角色与脱敏字段的关联（先删除后添加，如果desenseIds为null则只删除不添加）
     *
     * @param groupId
     * @param desenseIds
     * @return
     */
    public boolean createBatchGroupDesense(int groupId, List<Integer> desenseIds) {
        if (groupId <= 0)
            throw new IllegalArgumentException("param invalid groupId is :" + groupId + "  desenses is : " + desenseIds);
        try {
            groupBizService.createGroupBindDesense(groupId, desenseIds);

            redisPermissionUtil.desenseToRedis(groupId); //从写redis

            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 创建角色与权限的关联（先删除后添加，如果resourceIds为null则只删除不添加）

     * @return
     */
    public ResponseResult<Boolean> createBatchGroupResource(GroupBindVo vo) {
        ResponseResult<Boolean> result = new ResponseResult<>();
        if (vo.getGroupId() <= 0)
            return result.error("角色id不能为kong", Boolean.FALSE);
        if (GroupSystemTypeEnum.getEnum(vo.getGroupSystemType()) == null)
            return result.error("系统类型无效", Boolean.FALSE);

        //如果是车联网，那么调用车联网接口设置权限，op库里不保存车联网的权限
        if (vo.getGroupSystemType() == GroupSystemTypeEnum.IOV.getValue()) {
            try {
                ResponseResult<Boolean> iovResult = iovPermissionService.setPermission(vo.getGroupId(), vo.getDataIds());
                if (iovResult.getCode() != ResponseCodeEnum.SUCCESS.getCode() || !iovResult.getData()) { //同步失败
                    logger.error("调用车联网设置权限接口失败, 返回信息result ::{}", iovResult.getMessage());
                }
                return result.success("成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        } else {
            try {
                groupBizService.createBatchGroupResource(vo.getGroupId(), vo.getDataIds());

                Map<String, Object> getAccountGroupParam = new HashMap<>();
                getAccountGroupParam.put("groupId", vo.getGroupId());

                List<AccountGroupDto> accountGroupList = accountGroupService.getAccountGroupListByParam(getAccountGroupParam);
                if (CollectionUtils.isNotEmpty(accountGroupList)) {
                    final List<Integer> accountIds = new ArrayList<>();
                    accountGroupList.forEach(accountGroup -> {
                        accountIds.add(accountGroup.getAccountId());
                    });

                    Map<String, Object> getAccountParam = new HashMap<>();
                    getAccountParam.put("ids", accountIds);
                    List<AccountDto> accountList = accountService.getAccountByParam(getAccountParam);
                    accountList.forEach(account -> {  //强制登出
                        tokenUtil.deleteUserByAccount(account);
                    });
                }

                //重写redis中的权限
                redisPermissionUtil.resourceToRedis(vo.getGroupId(), GroupSystemTypeEnum.getEnum(vo.getGroupSystemType()));

                return result.success("成功", Boolean.TRUE);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        return result.error("失败", Boolean.FALSE);
    }

//    public boolean setResourceToRedisByGroup(int groupId) {
//
//    }
}
